#include "constantMedium.h"

ConstantMedium::ConstantMedium(shared_ptr<Hittable> boundary, double density, shared_ptr<Texture> tex)
    : boundary(boundary), neg_inv_density(-1 / density),
    phase_function(make_shared<Isotropic>(tex))
{}

ConstantMedium::ConstantMedium(shared_ptr<Hittable> boundary, double density, const Color& albedo)
    : boundary(boundary), neg_inv_density(-1 / density),
    phase_function(make_shared<Isotropic>(albedo))
{}
bool ConstantMedium::hit(const Ray& r, Interval ray_t, HitRecord& rec) const
{
    // Print occasional samples when debugging. To enable, set enableDebug true.
    const bool enableDebug = false;
    const bool debugging = enableDebug && random_double() < 0.00001;

    HitRecord rec1, rec2;

    if (!boundary->hit(r, Interval::universe, rec1))
        return false;

    if (!boundary->hit(r, Interval(rec1.t + 0.0001, infinity), rec2))
        return false;

    if (debugging) std::clog << "\nt_min=" << rec1.t << ", t_max=" << rec2.t << '\n';

    if (rec1.t < ray_t.min) rec1.t = ray_t.min;
    if (rec2.t > ray_t.max) rec2.t = ray_t.max;

    if (rec1.t >= rec2.t)
        return false;

    if (rec1.t < 0)
        rec1.t = 0;

    auto ray_length = r.direction().length();
    auto distance_inside_boundary = (rec2.t - rec1.t) * ray_length;
    auto hit_distance = neg_inv_density * log(random_double());

    if (hit_distance > distance_inside_boundary)
        return false;

    rec.t = rec1.t + hit_distance / ray_length;
    rec.p = r.at(rec.t);

    if (debugging) {
        std::clog << "hit_distance = " << hit_distance << '\n'
            << "rec.t = " << rec.t << '\n'
            << "rec.p = " << rec.p << '\n';
    }

    rec.normal = Vec3(1, 0, 0);  // arbitrary
    rec.front_face = true;     // also arbitrary
    rec.material = phase_function;

    return true;
}
